package com.wypiwyl.footastic.view;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import com.wypiwyl.footastic.Arena;
import com.wypiwyl.footastic.Direction;
import com.wypiwyl.footastic.Player;
import com.wypiwyl.footastic.PlayerKey;
import com.wypiwyl.footastic.R;
import com.wypiwyl.footastic.model.Util;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.MaskFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.PorterDuff.Mode;
import android.graphics.Region;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.ArcShape;
import android.graphics.drawable.shapes.OvalShape;
import android.graphics.drawable.shapes.PathShape;
import android.graphics.drawable.shapes.Shape;
import android.util.Log;

public class PlayerLayer extends AbstractLayer {

    // declaration log
    private static final String TAG = "PlayerLayer";

    //FIXME
    // taille d'une case
    private static final int D_CASE = 42;
    public static final int W_CASE = D_CASE;
    public static final int H_CASE = D_CASE;

    /** declaration des images statiques **/
    // declaration des images des joueurs de l'equipe A
    private static Drawable img_playerA;
    private static Drawable img_playerASelected;
    // declaration des images des joueurs de l'equipe B
    private static Drawable img_playerB;
    private static Drawable img_playerBSelected;
    // declaration des images pour les numeros des joueurs
    private static Drawable[] t_img_player_num;


    /** declaration des images propres au joueur **/
    // declaration de l'image du maillot
    private final Drawable img_player;
    private final Drawable img_player_selected;
    // declaration de l'image du numero
    private final Drawable img_player_num;

    //
    private final Paint mPaintPathPlayer = new Paint();
    private final Paint mPaintPathCircle = new Paint();
    private final Paint mPaintPathBlur = new Paint();
    private MaskFilter mMaskFilterPath = new BlurMaskFilter(6, BlurMaskFilter.Blur.INNER);

    private final Paint paintInfo = new Paint();

    /** declaration des donnees **/
    // declaration du joueur associe
    private Player player;
    // declaration des dimensions du claque
    private int widthLayer;
    private int heightLayer;

    //    public List<Point> lPointPlayer;

    // declaration de variable memorisant les deplacements du joueur
    private Path mPathPlayer = new Path();
    private Path mPathCircle = new Path();
    private List<Point> mListPosition = new ArrayList<Point>();

    // distance parcourue par le joueur dans un tour
    private int distancePlayer;
    //
    int indexPointPlayer;

    private float mX, mY;
    private static final float TOUCH_TOLERANCE = 4;

    public PlayerLayer(Player _player, int _width, int _height, Context _context) {

        /** initialisation des images statiques **/
        // initialisation des images des joueurs de l'equipe A
        img_playerA = _context.getResources().getDrawable(R.raw.player1);
        img_playerASelected = _context.getResources().getDrawable(R.raw.player1_selected);
        // initialisation des images des joueurs de l'equipe B
        img_playerB = _context.getResources().getDrawable(R.raw.player2);
        img_playerBSelected = _context.getResources().getDrawable(R.raw.player2_selected);
        // initialisation des images pour les numeros des joueurs
        t_img_player_num = new Drawable[22];
        t_img_player_num[1] = _context.getResources().getDrawable(R.raw.player_num_1);
        t_img_player_num[2] = _context.getResources().getDrawable(R.raw.player_num_2);
        t_img_player_num[3] = _context.getResources().getDrawable(R.raw.player_num_3);
        t_img_player_num[4] = _context.getResources().getDrawable(R.raw.player_num_4);
        t_img_player_num[5] = _context.getResources().getDrawable(R.raw.player_num_5);
        t_img_player_num[6] = _context.getResources().getDrawable(R.raw.player_num_6);
        t_img_player_num[7] = _context.getResources().getDrawable(R.raw.player_num_7);
        t_img_player_num[8] = _context.getResources().getDrawable(R.raw.player_num_8);
        t_img_player_num[9] = _context.getResources().getDrawable(R.raw.player_num_9);
        t_img_player_num[10] = _context.getResources().getDrawable(R.raw.player_num_10);
        t_img_player_num[11] = _context.getResources().getDrawable(R.raw.player_num_11);


        // initialisation des images
        if (_player.isbTeamA()) {
            this.img_player = img_playerA;
            this.img_player_selected = img_playerASelected;
        } else {
            this.img_player = img_playerB;
            this.img_player_selected = img_playerBSelected;
        }

        /** initialisation du trait du chemin du joueur **/
        mPaintPathPlayer.setAntiAlias(true);
        mPaintPathPlayer.setDither(true);
        // methode de dessin, ici il ne s'agit que d'un trait
        mPaintPathPlayer.setStyle(Paint.Style.STROKE);
        mPaintPathPlayer.setStrokeJoin(Paint.Join.ROUND);
        mPaintPathPlayer.setStrokeCap(Paint.Cap.ROUND);
        // epaisseur du trait
        mPaintPathPlayer.setStrokeWidth(4);
        // choix des couleurs
        if (_player.isbTeamA()) {
            mPaintPathPlayer.setColor(Color.RED);
        } else {
            mPaintPathPlayer.setColor(Color.BLUE);
        }
        /** initialisation du trait du chemin du joueur **/
        // methode de dessin, ici on remplit
        mPaintPathCircle.setStyle(Paint.Style.FILL);
        mPaintPathCircle.setColor(Color.WHITE);

        mPaintPathBlur.setAntiAlias(true);
        mPaintPathBlur.setDither(true);
        // methode de dessin, ici il ne s'agit que d'un trait
        mPaintPathBlur.setStyle(Paint.Style.STROKE);
        mPaintPathBlur.setStrokeJoin(Paint.Join.ROUND);
        mPaintPathBlur.setStrokeCap(Paint.Cap.ROUND);
        // epaisseur du trait
        mPaintPathBlur.setStrokeWidth(6);
        // choix des couleurs
        if (_player.isbTeamA()) {
            mPaintPathBlur.setColor(Color.RED);
            mPaintPathBlur.setMaskFilter(mMaskFilterPath);
        } else {
            mPaintPathBlur.setColor(Color.BLUE);
        }

        this.img_player_num = t_img_player_num[_player.getNumPlayer()];

        /** initialisation des donnees **/
        // initialisation du joueur associe
        this.player = _player;
        // initialisation des dimensions du calque
        this.widthLayer = _width;
        this.heightLayer = _height;

        /** initialisation du chemin que va parcourir le joueur **/

        //        lPointPlayer = new ArrayList<Point>();
        //        // on intialise le chemin par le point ou est present le joueur
        //        lPointPlayer.add(getPosition());
        //
        indexPointPlayer = 0;
        paintInfo.setColor(Color.BLACK);
    }

    @Override
    public Rect getLayout() {
        return LayoutUtil.getCenterLayout(getPosition(), widthLayer, heightLayer);
    }

    public Rect getLayout(Point position) {
        return LayoutUtil.getCenterLayout(position, widthLayer, heightLayer);
    }

    @Override
    public void onDraw(Canvas canvas) {

        Log.v(TAG, this.getClass().getName() + ".onDraw" + " - BEGIN");

        /** affichage du cone d'interception si le joueur n'a pas le ballon **/
        //        if (!isPlayerOwnerBall()) {
        // affichage du cone d'interception
        drawSteal(canvas);
        //        }



        if ((player.isbTeamA() && Arena.getInstance().isTeamAShowMove()) || (!player.isbTeamA() && Arena.getInstance().isTeamBShowMove())) {
            // affichage du chemin
            drawPath(canvas);
        }
        
        // affichage du joueur
        drawPlayer(canvas);

        Log.v(TAG, this.getClass().getName() + ".onDraw" + " - END");
    }

    /*
     * dessine le joueur
     */
    private void drawPlayer(Canvas canvas) {

        // on recupere la position du joueur
        Point position = player.getPosition();

        // affichage du maillot
        if (isPlayerSelected()) {
            img_player_selected.setBounds(getLayout(position));
            img_player_selected.draw(canvas);
        } else {
            img_player.setBounds(getLayout(position));

            //          img_player_selected.setColorFilter(Color.WHITE, Mode.OVERLAY);

            //            if (Flags.getInstance().isPlayerShow(player)) {
            img_player.draw(canvas);
            //            }
            //            // on masque le maillot
            //            else {
            //                img_player.setAlpha(75);
            //                img_player.draw(canvas);
            //                img_player.setAlpha(100);
            //            }

        }

        // affichage du numero
        img_player_num.setBounds(getLayout(position));
        img_player_num.draw(canvas);

        // TODO : indication pour les dev, a enlever par la suite
        //        canvas.drawText(distancePlayer + "/" + lPointPlayer.size(), position.x, position.y, paintInfo);
    }

    /*
     * dessine le chemin d'un joueur
     */
    private void drawPath(Canvas canvas) {

        // on dessine le chemin
//        mPaintPath.setColor(Color.WHITE);
        mPaintPathPlayer.setStrokeWidth(3);
//        mPaintPath.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.OVERLAY));
        //
        canvas.drawPath(mPathPlayer, mPaintPathPlayer);
        //
        canvas.drawPath(mPathCircle, mPaintPathCircle);
        //
        canvas.drawPath(mPathCircle, mPaintPathPlayer);

        //        img_player_num.

        //        if (player.getPlayerKey().getNumPlayer() == 2) {
        //            // on dessine le chemin
        //            canvas.drawPath(mPathPlayer, mPaintPath);
        //        } else         if (player.getPlayerKey().getNumPlayer() == 3) {
        //            // on dessine le chemin
        //            mPaintPath.setColor(Color.WHITE);
        //            mPaintPath.setStrokeWidth(2);
        //            mPaintPath.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.OVERLAY));
        //            canvas.drawPath(mPathPlayer, mPaintPath);
        ////            mPaintPathBlur.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.OVERLAY));
        ////            canvas.drawPath(mPathPlayer, mPaintPathBlur);
        //        } else         if (player.getPlayerKey().getNumPlayer() == 4) {
        //            // on dessine le chemin
        //            canvas.drawPath(mPathPlayer, mPaintPath);
        //            canvas.drawPath(mPathPlayer, mPaintPathBlur);
        //        } else         if (player.getPlayerKey().getNumPlayer() == 5) {
        //            mPaintPath.setColor(Color.WHITE);
        //            mPaintPath.setStrokeWidth(2);
        //            mPaintPath.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.OVERLAY));
        //            canvas.drawPath(mPathPlayer, mPaintPath);
        //            canvas.drawPath(mPathPlayer, mPaintPath);
        //        } else         if (player.getPlayerKey().getNumPlayer() == 6) {
        //            // on dessine le chemin
        //            mPaintPath.setColor(Color.WHITE);
        //            mPaintPath.setStrokeWidth(2);
        //            mPaintPath.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.OVERLAY));
        //            canvas.drawPath(mPathPlayer, mPaintPath);
        //            mPaintPathBlur.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.OVERLAY));
        //            canvas.drawPath(mPathPlayer, mPaintPathBlur);
        //        } else         if (player.getPlayerKey().getNumPlayer() == 7) {
        //            // on dessine le chemin
        //            mPaintPath.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.OVERLAY));
        //            canvas.drawPath(mPathPlayer, mPaintPath);
        //            mPaintPathBlur.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.OVERLAY));
        //            canvas.drawPath(mPathPlayer, mPaintPathBlur);
        //        } else         if (player.getPlayerKey().getNumPlayer() == 8) {
        //            // on dessine le chemin
        //            mPaintPath.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.OVERLAY));
        //            canvas.drawPath(mPathPlayer, mPaintPath);
        //        } else         if (player.getPlayerKey().getNumPlayer() == 9) {
        //            // on dessine le chemin
        //            mPaintPath.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
        //            canvas.drawPath(mPathPlayer, mPaintPath);
        //        } else         if (player.getPlayerKey().getNumPlayer() == 10) {
        //            // on dessine le chemin
        //            mPaintPath.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DARKEN));
        //            canvas.drawPath(mPathPlayer, mPaintPath);
        //        } else         if (player.getPlayerKey().getNumPlayer() == 11) {
        //            // on dessine le chemin
        //            mPaintPath.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SCREEN));
        //            canvas.drawPath(mPathPlayer, mPaintPath);
        //        }

        //                /** on dessine les points intermediaires **/
        //                Point lastPoint = player.getPosition();
        //                // on itere sur les points pour dessiner les points intermediaires
        //                for (int i = indexPointPlayer; i < lPointPlayer.size() - 1; i++) {
        //                    // on recupere le point
        //                    Point position = lPointPlayer.get(i + 1);
        //                    // condition pour dessiner les intervalles entre les points intermediaires
        //                    if (i % 5 == 0) {
        //        
        //                        // on calcule la distance entre l'ancien point et le nouveau que l'on veut afficher
        //                        int distance = Util.getDistance(lastPoint, position);
        //        
        //                        Paint paintPoint = new Paint();
        //                        paintPoint.setColor(Color.YELLOW);
        //        
        //                        // on dessine le point sur le segment
        //                        canvas.drawCircle(position.x, position.y, 4, paintPoint);
        //                        // on reaffecte le dernier point
        //                        lastPoint = position;
        //                    }
        //                }
    }

    /*
     * dessine le cercle d'interception d'un joueur
     */
    private void drawSteal(Canvas canvas) {

        int angleInterception = player.getAngleInterception();
        int rayonInterception = player.getRayonInterception();

        Rect rectF = new Rect(player.getPosition().x - rayonInterception, player.getPosition().y - rayonInterception, player.getPosition().x + rayonInterception, player.getPosition().y
                + rayonInterception);

        ShapeDrawable mDrawable = new ShapeDrawable(new ArcShape(player.getDirection() - (angleInterception / 2), angleInterception));
        mDrawable.getPaint().setColor(Color.WHITE);
        mDrawable.setAlpha(100);

        //        if (isPlayerSelected()) {
        //          mDrawable.setColorFilter(Color.WHITE, Mode.OVERLAY);            
        //        }

        mDrawable.setBounds(rectF);
        mDrawable.draw(canvas);
    }

    // TODO : revoir cette initiaisation
    public void initRound() {
        // on efface le chemin du joueur
        initMove();
        // on re-intialise le chemin par le point ou est present le joueur
        //        lPointPlayer.add(getPosition());
        // on re-initialise l'index du point sur lequel le joueur se trouve (pour les deplacements)
        indexPointPlayer = 0;
        distancePlayer = 0;
    }
    
    // TODO : revoir cette initiaisation
    public void initMove() {
        // on efface le chemin du joueur
        mPathPlayer.reset();
        mPathCircle.reset();
        mListPosition.clear();
    }

    public boolean isPassing(Point positionEvent) {

        int rayon = 300;

        Path path = new Path();
        path.moveTo(rayon, 0);
        path.lineTo(0, rayon);
        path.lineTo(rayon, 2 * rayon);
        path.lineTo(2 * rayon, rayon);
        path.close();

        Rect rectF = new Rect(player.getPosition().x - (rayon / 2), player.getPosition().y - (rayon / 2), player.getPosition().x + (rayon / 2), player.getPosition().y + (rayon / 2));

        //        RectF rectF2 = new RectF();
        //        path.computeBounds(rectF2, true);
        Region region = new Region();
        //        region.setPath(path, new Region((int) rectF2.left, (int) rectF2.top, (int) rectF2.right, (int) rectF2.bottom));
        region.setPath(path, new Region(rectF));

        boolean test = region.contains(positionEvent.x, positionEvent.y);

        return test;
    }

    public void initPath(Point position) {

        initMove();
        
        mPathPlayer.moveTo(position.x, position.y);
        mX = position.x;
        mY = position.y;
    }

    public void recordPath(Point position) {

        //        // TODO
        //        int distanceMax = 0;
        //        
        //        if (Arena.getInstance().getOwnerBall() != null && Arena.getInstance().getOwnerBall().equals(player.getPlayerKey())) {
        //            distanceMax = (int)player.getDistanceMax()/2;
        //        } else {
        //            distanceMax = player.getDistanceMax();
        //        }
        //        
        //        
        //        if (lPointPlayer.size() < player.getDexteriteBalleAuPied() && distancePlayer < distanceMax) {
        //            distancePlayer += Util.getDistance(position, lPointPlayer.get(lPointPlayer.size() - 1));
        //            lPointPlayer.add(position);
        //        }

        
        if (mListPosition.size() == 0) {
            // on ajoute la position initiale du joueur
            mListPosition.add(player.getPosition());
        }
        
        int distance = 0;
        // calcul de la distance deja parcourue
        for (int i = 0; i < mListPosition.size() - 1 && mListPosition.size() > 1; i++) {
            Point begin = mListPosition.get(i);
            Point end = mListPosition.get(i+1);
            // ajout de la distance entre les 2 positions
            distance += Util.getDistance(begin, end);
        }
        // ajout de la nouvelle distance
        distance += Util.getDistance(mListPosition.get(mListPosition.size() - 1), position);
        
        
        if (distance < player.getSpeed()) {
            float dx = Math.abs(position.x - mX);
            float dy = Math.abs(position.y - mY);
            if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
                // on enregistre le chemin
                mPathPlayer.quadTo(mX, mY, (position.x + mX) / 2, (position.y + mY) / 2);
                // TODO mettre une variable du joueur pour controler la frequence des cercles ?
                // on enegistre le cercle
                mPathCircle.addCircle(position.x, position.y, 6, android.graphics.Path.Direction.CW);

                mX = position.x;
                mY = position.y;
            }
            // on enregistre la position
            mListPosition.add(position);
        }
    }

    public void endPath(Point position) {
        mPathPlayer.lineTo(mX, mY);

    }

    private boolean isPlayerSelected() {
        return Flags.getInstance().isPlayerSelected() && Flags.getInstance().getPlayerKeySelected().equals(player.getPlayerKey());
    }

    private boolean isNotPlayerSelected() {
        return Flags.getInstance().isPlayerSelected() && !Flags.getInstance().getPlayerKeySelected().equals(player.getPlayerKey());
    }

    private Point getPosition() {
        return getPlayer().getPosition();
    }

    public Player getPlayer() {
        return player;
    }

    public int getNbSequence() {
        return mListPosition.size();
    }

    public List<Point> getmListPosition() {
        return mListPosition;
    }
    
    
}
